package com.neusoft.bizcore.webauth.secret.oauth2;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

public class OAuth2AuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private static ObjectMapper mapper;

    public static final String OAUTH2_AUTHCODE_KEY = "code";

    private String codeParameter = OAuth2AuthenticationFilter.OAUTH2_AUTHCODE_KEY;

    static {
        OAuth2AuthenticationFilter.mapper = new ObjectMapper();
    }

    public OAuth2AuthenticationFilter() {
        super(new AntPathRequestMatcher("/oauth2login"));
    }

    @Override
    public Authentication attemptAuthentication(final HttpServletRequest request, final HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {
        final String body = StreamUtils.copyToString(request.getInputStream(), Charset.forName("UTF-8"));
        String code = null;
        if (StringUtils.hasText(body)) {

            final JavaType javaType = OAuth2AuthenticationFilter.mapper.getTypeFactory()
                    .constructParametricType(HashMap.class, String.class, String.class);
            final Map<String, String> jsonObj =
                    OAuth2AuthenticationFilter.mapper.readValue(body, javaType);
            code = this.obtainCode(jsonObj);
        } else {
            code = request.getParameter(this.codeParameter);
        }

        if (code == null) {
            code = "";
        }

        code = code.trim();
        final OAuth2AuthenticationToken authRequest = new OAuth2AuthenticationToken(
                code, code);
        return this.getAuthenticationManager().authenticate(authRequest);
    }

    protected String obtainCode(final Map<String, String> jsonObj) {
        return jsonObj.get(this.codeParameter);
    }

    public void setCodeParameter(final String codeParameter) {
        Assert.hasText(this.codeParameter, "code parameter must not be empty or null");
        this.codeParameter = codeParameter;
    }

    public final String getCodeParameter() {
        return this.codeParameter;
    }

}
